package com.yntsoft.mybatisUtil;


import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Properties;
import org.apache.commons.lang.StringUtils;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;


public class BasePagination {
    private String databaseType;

    protected String getPageSql(Page<?> page, String sql) {
        if (page != null) if ((StringUtils.isNotEmpty(page.getSortName()))
                              && (StringUtils.isNotEmpty(page.getOrder()))) {
            sql = sql + " order by " + page.getSortName() + " " + page.getOrder();
            if (StringTools.isNotEmptyString(page.getAssembleOrderBy()))
                sql = sql + "," + page.getAssembleOrderBy();
        } else if (StringTools.isNotEmptyString(page.getAssembleOrderBy())) {
            sql = sql + " order by " + page.getAssembleOrderBy();
        }
        StringBuffer sqlBuffer = new StringBuffer(sql);
        if ("mysql".equalsIgnoreCase(this.databaseType)) return getMysqlPageSql(page, sqlBuffer);
        if ("oracle".equalsIgnoreCase(this.databaseType)) return getOraclePageSql(page, sqlBuffer);
        return sqlBuffer.toString();
    }

    protected String getMysqlPageSql(Page<?> page, StringBuffer sqlBuffer) {
        int offset = (page.getPageNo() - 1) * page.getPageSize();
        sqlBuffer.append(" limit ").append(offset).append(",").append(page.getPageSize());
        return sqlBuffer.toString();
    }

    protected String getOraclePageSql(Page<?> page, StringBuffer sqlBuffer) {
        int offset = (page.getPageNo() - 1) * page.getPageSize() + 1;
        sqlBuffer.insert(0, "select u.*, rownum r from (").append(") u where rownum < ").append(
            offset + page.getPageSize());
        sqlBuffer.insert(0, "select * from (").append(") where r >= ").append(offset);
        return sqlBuffer.toString();
    }

    protected void setTotalRecord(Page<?> page, MappedStatement mappedStatement,
                                  Connection connection) {
        BoundSql boundSql = mappedStatement.getBoundSql(page);
        String sql = boundSql.getSql();
        String countSql = getCountSql(sql);
        List parameterMappings = boundSql.getParameterMappings();
        BoundSql countBoundSql = new BoundSql(mappedStatement.getConfiguration(), countSql,parameterMappings, page);
        ParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, page,countBoundSql);
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            pstmt = connection.prepareStatement(countSql);
            parameterHandler.setParameters(pstmt);
            rs = pstmt.executeQuery();
            if (rs.next()) {
                int totalRecord = rs.getInt(1);
                page.setTotal(totalRecord);
            }
        } catch (SQLException e) {
            e.printStackTrace();
            try {
                if (rs != null) rs.close();
                if (pstmt != null) pstmt.close();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        } finally {
            try {
                if (rs != null) rs.close();
                if (pstmt != null) pstmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    protected String getCountSql(String sql) {
        int index = sql.toLowerCase().indexOf("from");
        return "select count(*) " + sql.substring(index);
    }

    public String getDatabaseType() {
        return this.databaseType;
    }

    public void setDatabaseType(String databaseType) {
        this.databaseType = databaseType;
    }

    public void setProperties(Properties properties) {
        this.databaseType = properties.getProperty("databaseType");
    }
}